/*

 * Copyright (C) 2021 Huawei Device Co., Ltd.

 * Licensed under the Apache License, Version 2.0 (the "License");

 * you may not use this file except in compliance with the License.

 * You may obtain a copy of the License at

 *

 *     http://www.apache.org/licenses/LICENSE-2.0

 *

 * Unless required by applicable law or agreed to in writing, software

 * distributed under the License is distributed on an "AS IS" BASIS,

 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

 * See the License for the specific language governing permissions and

 * limitations under the License.

 */
package com.jaiky.imagespickers.camera;

import com.jaiky.imagespickers.ImagePicker;
import com.jaiky.imagespickers.ResourceTable;
import com.jaiky.imagespickers.utils.FileUtils;
import com.jaiky.imagespickers.utils.Options;
import ohos.aafwk.ability.Ability;
import ohos.aafwk.content.Intent;
import ohos.aafwk.content.Operation;
import ohos.agp.animation.Animator;
import ohos.agp.animation.AnimatorProperty;
import ohos.agp.colors.RgbColor;
import ohos.agp.components.Component;
import ohos.agp.components.DependentLayout;
import ohos.agp.components.Image;
import ohos.agp.components.StackLayout;
import ohos.agp.components.element.PixelMapElement;
import ohos.app.dispatcher.TaskDispatcher;
import ohos.app.dispatcher.task.Revocable;
import ohos.eventhandler.EventHandler;
import ohos.eventhandler.EventRunner;
import ohos.global.resource.NotExistException;
import ohos.media.camera.params.Metadata;
import ohos.media.image.ImageReceiver;
import ohos.media.image.common.ImageFormat;
import ohos.multimodalinput.event.TouchEvent;
import ohos.utils.net.Uri;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Calendar;

public class CameraPhotoAbility extends Ability implements Component.ClickedListener {
    /**
     * Pix选中的图片的list集合
     */
    private EventHandler cameraEventHandler;
    private EventHandler mainHandler;
    private CameraView cameraView;
    private String picturePath;
    private int flashMode = Metadata.FlashMode.FLASH_CLOSE;
    // 定义生成图片文件名
    private String pictureName = "picture_001.jpg";
    private Image takePic;
    private Image takePicBg;
    private StackLayout bottomButtons;
    private StackLayout flash;
    private StackLayout shiftCamera;
    private Options options = null;
    private TaskDispatcher mParallelTaskDispatcher;
    private Revocable mRevocable;
    private DependentLayout selectImage;
    private Image previewPhoto;
    private Image back;
    private Image confirm;
    private File myFile;
    private String absolutePath;
    private ImageReceiver imageReceiver;
    // 单帧捕获生成图像回调Listener
    private final ImageReceiver.IImageArrivalListener imageArrivalListener = new ImageReceiver.IImageArrivalListener() {
        @Override
        public void onImageArrival(ImageReceiver imageReceiver1) {
            imageReceiver = imageReceiver1;
            pictureName = Calendar.getInstance().getTimeInMillis() + ".jpg";
            // 创建图片文件
            myFile = new File(picturePath, pictureName);
            absolutePath = null;
            try {
                absolutePath = myFile.getCanonicalPath();
            } catch (IOException e) {
                e.printStackTrace();
            }
            ohos.media.image.Image myImage = imageReceiver.readNextImage();
            ohos.media.image.Image.Component component = myImage.getComponent
                    (ImageFormat.ComponentType.JPEG);
            byte[] bytes = new byte[component.remaining()];
            component.read(bytes);
            FileOutputStream output = null;
            try {
                output = new FileOutputStream(myFile);
                // 写图像数据
                output.write(bytes);
                output.flush();
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                myImage.release();
                if (output != null) {
                    try {
                        // 关闭流
                        output.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
            mainHandler.postTask(new Runnable() {
                @Override
                public void run() {
                    bottomButtons.setVisibility(Component.HIDE);
                    cameraView.setVisibility(Component.HIDE);
                    selectImage.setVisibility(Component.VISIBLE);
                    ImagePicker.getInstance().getImageLoader().displayImage(CameraPhotoAbility.this, absolutePath, previewPhoto);
                }
            });
        }
    };

    private void save(ImageReceiver imageReceiver, File myFile, String absolutePath) {
        // 创建一个读写线程任务用于保存图片
        ImageSaver imageSaver = new ImageSaver(imageReceiver.readNextImage(), myFile);
        // 执行读写线程任务生成图片
        cameraEventHandler.postTask(imageSaver);
    }

    @Override
    public void onStart(Intent intent) {
        super.onStart(intent);
        getWindow().setTransparent(true);
        getWindow().setBackgroundColor(new RgbColor(0xffffffff));
        setUIContent(ResourceTable.Layout_ability_camera);
        options = intent.getSerializableParam("options");
        mainHandler = new EventHandler(EventRunner.getMainEventRunner());
        if (options == null) {
            throw new SecurityException("options must not be null!");
        }
        File dir = getExternalFilesDir(options.getPath());
        if (!dir.exists()) {
            if (!dir.mkdir()) {
                // 创建文件夹失败
                terminateAbility();
            }
        }
        picturePath = dir + "/";
        initView();
    }

    private void initView() {
        setDisplayOrientation(options.getScreenOrientation());
        if (findComponentById(ResourceTable.Id_camera_view) instanceof CameraView) {
            cameraView = (CameraView) findComponentById(ResourceTable.Id_camera_view);
        }
        cameraView.setFrontCamera(options.isFrontfacing());
        cameraView.setImageArrivalListener(imageArrivalListener);

        if (findComponentById(ResourceTable.Id_take_pic_bg) instanceof Image) {
            takePicBg = (Image) findComponentById(ResourceTable.Id_take_pic_bg);
        }
        if (findComponentById(ResourceTable.Id_take_pic) instanceof Image) {
            takePic = (Image) findComponentById(ResourceTable.Id_take_pic);
        }
        takePic.setClickedListener(component -> {
            if (options.getMode() == Options.Mode.VIDEO) {
                return;
            }
            // 拍照
            cameraView.capture();
        });
        takePic.setTouchEventListener(new Component.TouchEventListener() {
            @Override
            public boolean onTouchEvent(Component component, TouchEvent touchEvent) {
                if (touchEvent.getAction() == TouchEvent.PRIMARY_POINT_DOWN) {
                    takePicBg.setVisibility(Component.VISIBLE);
                }
                if (touchEvent.getAction() == TouchEvent.PRIMARY_POINT_UP) {
                    takePicBg.setVisibility(Component.HIDE);
                }
                return true;
            }
        });
        if (findComponentById(ResourceTable.Id_bottomButtons) instanceof StackLayout) {
            bottomButtons = (StackLayout) findComponentById(ResourceTable.Id_bottomButtons);
        }
        if (findComponentById(ResourceTable.Id_flash) instanceof StackLayout) {
            flash = (StackLayout) findComponentById(ResourceTable.Id_flash);
        }
        if (findComponentById(ResourceTable.Id_front) instanceof StackLayout) {
            shiftCamera = (StackLayout) findComponentById(ResourceTable.Id_front);
        }
        selectImage = (DependentLayout) findComponentById(ResourceTable.Id_select_image);
        previewPhoto = (Image) findComponentById(ResourceTable.Id_image_view);
        back = (Image) findComponentById(ResourceTable.Id_back);
        confirm = (Image) findComponentById(ResourceTable.Id_confirm);
        flash.setClickedListener(this);
        shiftCamera.setClickedListener(this);
        back.setClickedListener(this);
        confirm.setClickedListener(this);
        cameraEventHandler = new EventHandler(EventRunner.create("TakePictureAbilitySlice"));
        initData();
    }

    private void initData() {
    }

    @Override
    public void onClick(Component component) {
        int id = component.getId();
        if (id == ResourceTable.Id_flash) {
            // 闪光灯
            int height = flash.getHeight();
            if (flash.getComponentAt(0) instanceof Image) {
                Image iv = (Image) flash.getComponentAt(0);
                flash.createAnimatorProperty().moveToY(height).setDuration(100)
                        .setStateChangedListener(new Animator.StateChangedListener() {
                            @Override
                            public void onStart(Animator animator) {
                            }

                            @Override
                            public void onStop(Animator animator) {
                            }

                            @Override
                            public void onCancel(Animator animator) {
                            }

                            @Override
                            public void onEnd(Animator animator) {
                                iv.setTranslationY(-(height / 2));
                                if (flashMode == Metadata.FlashMode.FLASH_AUTO) {
                                    flashMode = Metadata.FlashMode.FLASH_CLOSE;
                                    try {
                                        PixelMapElement flashDrawable =
                                                new PixelMapElement(getResourceManager()
                                                        .getResource(ResourceTable.Media_flash_off));
                                        iv.setBackground(flashDrawable);
                                    } catch (IOException | NotExistException e) {
                                        e.printStackTrace();
                                    }
                                } else if (flashMode == Metadata.FlashMode.FLASH_CLOSE) {
                                    flashMode = Metadata.FlashMode.FLASH_ALWAYS_OPEN;
                                    try {
                                        PixelMapElement flashDrawable =
                                                new PixelMapElement(getResourceManager()
                                                        .getResource(ResourceTable.Media_flash_on));
                                        iv.setBackground(flashDrawable);
                                    } catch (IOException | NotExistException e) {
                                        e.printStackTrace();
                                    }
                                } else {
                                    flashMode = Metadata.FlashMode.FLASH_AUTO;
                                    try {
                                        PixelMapElement flashDrawable =
                                                new PixelMapElement(getResourceManager()
                                                        .getResource(ResourceTable.Media_flash_auto));
                                        iv.setBackground(flashDrawable);
                                    } catch (IOException | NotExistException e) {
                                        e.printStackTrace();
                                    }
                                }
                                cameraView.setCameraFlashMode(flashMode);
                                iv.createAnimatorProperty().moveToY(0).setDuration(50)
                                        .setStateChangedListener(null).start();
                            }

                            @Override
                            public void onPause(Animator animator) {
                            }

                            @Override
                            public void onResume(Animator animator) {
                            }
                        }).start();
            }
        }
        if (id == ResourceTable.Id_front) {
            // 切换摄像头
            AnimatorProperty animatorProperty = shiftCamera.createAnimatorProperty();
            animatorProperty.scaleXFrom(1).scaleX(0).setDuration(150)
                    .setStateChangedListener(new Animator.StateChangedListener() {
                        @Override
                        public void onStart(Animator animator) {
                        }

                        @Override
                        public void onStop(Animator animator) {
                        }

                        @Override
                        public void onCancel(Animator animator) {
                        }

                        @Override
                        public void onEnd(Animator animator) {
                            animatorProperty.scaleXFrom(0).scaleX(1).setDuration(150)
                                    .setStateChangedListener(null).start();
                        }

                        @Override
                        public void onPause(Animator animator) {
                        }

                        @Override
                        public void onResume(Animator animator) {
                        }
                    }).start();
            cameraView.switchCamera();
        }
        if (id == ResourceTable.Id_back) {
            bottomButtons.setVisibility(Component.VISIBLE);
            cameraView.setVisibility(Component.VISIBLE);
            selectImage.setVisibility(Component.HIDE);
            if (myFile != null) {
                boolean delete = myFile.delete();
            }
        }
        if (id == ResourceTable.Id_confirm) {
            save(imageReceiver, myFile, absolutePath);
        }
    }

    private void returnImages(Uri img) {
        Intent fileIntent = new Intent();
        fileIntent.setParam("extra_result_items", img + "");
        setResult(1001, fileIntent);
        terminateAbility();
    }


    /**
     * 开启Pix
     *
     * @param ability ability
     * @param options options
     */
    public static void start(Ability ability, Options options) {
        Intent intent = new Intent();
        Operation operation = new Intent.OperationBuilder()
                .withDeviceId("")
                .withBundleName(ability.getBundleName())
                .withAbilityName(CameraPhotoAbility.class.getName())
                .build();
        intent.setOperation(operation);
        intent.setParam("options", options);
        ability.startAbilityForResult(intent, options.getRequestCode());
    }

    /**
     * 开启Pix
     *
     * @param ability     ability
     * @param requestCode requestCode
     */
    public static void start(Ability ability, int requestCode) {
        start(ability, Options.init().setRequestCode(requestCode).setCount(1));
    }

    @Override
    public void onActive() {
        super.onActive();
    }

    @Override
    protected void onStop() {
        super.onStop();
        // 取消异步任务
        if (mRevocable != null) {
            mRevocable.revoke();
        }
        if (mParallelTaskDispatcher != null) {
            mParallelTaskDispatcher = null;
        }
    }

    // 保存图片, 图片数据读写，及图像生成见run方法
    private class ImageSaver implements Runnable {
        private final ohos.media.image.Image myImage;
        private final File myFile;

        ImageSaver(ohos.media.image.Image image, File file) {
            myImage = image;
            myFile = file;
        }

        @Override
        public void run() {
            try {
                Uri uri = FileUtils.saveImageToGallery(pictureName,
                        FileUtils.getPixMap(myFile.getCanonicalPath()), CameraPhotoAbility.this);
                returnImages(uri);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
